package com.simple.search;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.simple.util.SpringBeanUtil;

public class SearchUtil {
	
	private JSONObject jsonObject;
	
	private static Pattern pattern = Pattern.compile("\\$\\{\\w+\\}");
	
	private static Pattern numPattern = Pattern.compile("\\\"\\$\\[\\w+\\]\\\"");
	
	private static Map<String, String> typeMap = new HashMap<>();
	
	private static String host = "";//"http://192.168.1.69:9200";


	static {
		typeMap.put("get", "GET");
		typeMap.put("post", "POST");
		typeMap.put("put", "PUT");
		typeMap.put("delete", "DELETE");
		typeMap.put("head", "HEAD");
	}
	
	public SearchUtil(InputStream inputStream) {
		BufferedReader br = null;
		try {
			br = new BufferedReader(new InputStreamReader(inputStream, "utf-8"));
			StringBuffer buffer = new StringBuffer();
			String line = null;
			while((line = br.readLine()) != null) {
				buffer.append(line);
			}
			jsonObject = JSON.parseObject(buffer.toString());
			host = ((ElasticsearchCfg)SpringBeanUtil.getBean("elasticsearchCfg")).getHost();
		}
		catch(Exception e) {
			throw new RuntimeException(e);
		}
		finally {
			if(br != null) {
				try {
					br.close();
				}
				catch(Exception e) {}
			}
		}
	}
	
	public JSONObject executeBulk(String key, Map<String, String> urlParam, List<Map<String, String>> bodyParamList) {
		JSONObject requestObject = jsonObject.getJSONObject(key);
		if(requestObject == null) {
			throw new RuntimeException("请配置请求");
		}
		String type = requestObject.getString("type");
		String url = requestObject.getString("url");
		String action = requestObject.getJSONObject("action").toJSONString();
		String requestBody = null;
		JSONObject dataObject = requestObject.getJSONObject("data");
		if(url != null && urlParam != null && !urlParam.isEmpty()) {
			url = processTemplateString(url, urlParam);
		}
		if(dataObject != null) {
			requestBody = dataObject.toJSONString();
		}
		else {
			throw new RuntimeException("请配置data");
		}
		StringBuffer buffer = new StringBuffer();
		for(Map<String, String> param: bodyParamList) {
			buffer.append(processTemplate(action, param)+"\n");
			String temp = processTemplate(requestBody, param);
			buffer.append(temp+"\n");
		}
		JSONObject resultObject = execute(type, url, buffer.toString());
		if(resultObject.getIntValue("code") != 200) {
			throw new RuntimeException(resultObject.getString("message"));
		}
		JSONObject returnObject = resultObject.getJSONObject("data");
		if(returnObject.getBooleanValue("errors")) {
			throw new RuntimeException(returnObject.toJSONString());
		}
		return resultObject;
	}
	
	public JSONObject execute(String key, Map<String, String> params) {
		JSONObject requestObject = jsonObject.getJSONObject(key);
		if(requestObject == null) {
			throw new RuntimeException("请配置请求");
		}
		String type = requestObject.getString("type");
		String url = requestObject.getString("url");
		String requestBody = null;
		JSONObject dataObject = requestObject.getJSONObject("data");
		if(dataObject != null) {
			requestBody = dataObject.toJSONString();
		}
		if(requestBody != null && params != null && !params.isEmpty()) {
			requestBody = processTemplate(requestBody, params);
		}
		if(url != null && params != null && !params.isEmpty()) {
			url = processTemplateString(url, params);
		}
		return execute(type, url, requestBody);
	}
	
	public JSONObject execute(String key) {
		return execute(key, new HashMap<String, String>());
	}
	
	public JSONObject execute(String type, String url) {
		return execute(type, url, null);
	}
	
	public JSONObject execute(String type, String url, String requestBody) {
		type = typeMap.get(type);
		if(type == null) {
			throw new RuntimeException("type 只能是 get post put delete的一种");
		}
		if(host == null) {
			throw new RuntimeException("请配置elasticsearch的url");
		}
		return getHttpString(host + url, type, 3000, 20000, requestBody);
	}
	
	private static String processTemplate(String template, Map<String, String> params){
		Matcher m = numPattern.matcher(template);
	    StringBuffer sb = new StringBuffer();
	    while (m.find()) {
	        String param = m.group();
	        String key = param.substring(3, param.length() - 2);
	        String value = params.get(key);
	        if(value == null) {
	        	throw new RuntimeException("模版解析错误，缺少参数"+key);
	        }
	        m.appendReplacement(sb, value);
	    }
	    m.appendTail(sb);
	    return processTemplateString(sb.toString(), params);
	}
	
	private static String processTemplateString(String template, Map<String, String> params){
		Matcher m = pattern.matcher(template);
	    StringBuffer sb = new StringBuffer();
	    while (m.find()) {
	        String param = m.group();
	        String key = param.substring(2, param.length() - 1);
	        String value = params.get(key);
	        if(value == null) {
	        	throw new RuntimeException("模版解析错误，缺少参数"+key);
	        }
	        value = Matcher.quoteReplacement(SearchUtil.coverToJsonString(value));
	        m.appendReplacement(sb, value);
	    }
	    m.appendTail(sb);
	    return sb.toString();
	}
	
	
	private static JSONObject getHttpString(String url, String method, int connectTimeout, int readTimeout, String requestBody){
		
		HttpURLConnection connection = null;
		String returnString = null;
		JSONObject jsonObject = new JSONObject();
		BufferedReader in = null;
		try {
			URL requestUrl = new URL(url);
			connection = (HttpURLConnection) requestUrl.openConnection();
			connection.setConnectTimeout(connectTimeout);
			connection.setReadTimeout(readTimeout);
			connection.setRequestMethod(method);
			connection.setRequestProperty("Content-Type", "application/json");
			connection.setUseCaches(false);
			connection.setDoInput(true);
			if(requestBody != null){
				connection.setDoOutput(true);
				byte[] bytes = requestBody.getBytes("UTF-8");
				connection.getOutputStream().write(bytes);
			}
			int statusCode = connection.getResponseCode();
			jsonObject.put("code", statusCode);
			if (statusCode == 200 || statusCode == 201) {
				in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "utf-8"));
				StringBuilder result = new StringBuilder();
				String line;
				long time = System.currentTimeMillis();
				while (System.currentTimeMillis() - time < readTimeout && (line = in.readLine()) != null) {
					result.append(line);
				}
				returnString = result.toString();
				jsonObject.put("data", JSON.parse(returnString));
			} else {
				in = new BufferedReader(new InputStreamReader(connection.getErrorStream(), "utf-8"));
				StringBuilder result = new StringBuilder();
				String line;
				long time = System.currentTimeMillis();
				while (System.currentTimeMillis() - time < readTimeout && (line = in.readLine()) != null) {
					result.append(line);
				}
				returnString = result.toString();
				jsonObject.put("message", statusCode + returnString);
			}
			disconnection(connection, in);
		} catch (Exception e) {
			disconnection(connection, in);
			throw new RuntimeException(e);
		}
		return jsonObject;
	}

	private static void disconnection(HttpURLConnection connection, BufferedReader in) {
		if (in != null) {
			try {
				in.close();
			} catch (Exception e) {

			}
		}
		if (connection != null) {
			try {
				connection.disconnect();
			} catch (Exception e) {

			}
		}
	}
	
	public static String coverToJsonString(String text) {
		JSONObject json = new JSONObject();
		json.put("a", text);
		String s = json.toJSONString();
		s = s.substring(6, s.length() - 2);
		return s;
	}
}
